package com.opta.score;

import com.opta.entity.Line;
import com.opta.entity.OrderSolution;
import com.opta.entity.TaskOrder;
import org.optaplanner.core.api.score.buildin.bendable.BendableScore;
import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 2 * @Author: GuanChong
 * 3 * @Date: 2020/10/12 11:52
 * 4
 */
public class TaskOrderEasyScoreCalculator implements EasyScoreCalculator<OrderSolution> {

    @Override
    public BendableScore calculateScore(OrderSolution orderSolution) {
        /**
         * 隐藏硬约束 任务物料必须排在可生产的班组上  并且 不能超产能 并且日期在班组日期产能之后
         */
        int hardScore1 = 0;
        /**
         * 超产能
         */
        int hardScore2 = 0;
        /**
         * 不能空产 针对线体？
         */
        int softScore1 = 0;
        /**
         * 保证交期，即在最晚开始时间之前排产（软约束）
         */
        int softScore2 = 0;
        /**
         * 物料号可生产的班组
         * key:   物料号 materialCode
         * value: 班组   team集合
         */
        Map<String, Map<String, Double>> materialProducibleTeamMap = orderSolution.getMaterialProducibleTeamMap();

        /**
         * 共有多少个线体
         */
        int lineNumber = orderSolution.getLines().size();
        for (TaskOrder order : orderSolution.getOrders()) {


            // 赋值soft1
            Integer soft1Val = 0;
            if (order.getLine() != null) {
                //班组节拍数据
                Map<String, Double> teamsMap = materialProducibleTeamMap.get(order.getModelInfos().getMaterialCode());
                //计算hardScore 必须为可生产的机型
                if (teamsMap == null || teamsMap.isEmpty()) {
                    hardScore1 -= order.getOrderQty();
                } else {
                    //该order 的物料号所能生产的班组
                    List<String> teams = new ArrayList<>(16);
                    teamsMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(e -> teams.add(e.getKey()));
                    if (!teams.contains(order.getLine().getTeam())) {
                        hardScore1 -= order.getOrderQty();
                    }
                }

                //计算soft2  保证交期 即在最晚开始时间之前排产
                if (order.getLine().getDate().isAfter(order.deliveryDate)) {
                    softScore2 -= order.getOrderQty();
                }

                //计算soft1  计算空产总数
                List<Line> scheduledLines = orderSolution.getOrders().stream().map(TaskOrder::getLine).collect(Collectors.toList());
                scheduledLines = scheduledLines.stream().filter(s -> s != null && s.getLineId() != null).collect(Collectors.toList());
                List<String> scheduledLinesStr = scheduledLines.stream().map(s -> s.getLineId()).distinct().collect(Collectors.toList());
                Integer sd = 0;
                if (scheduledLinesStr != null && !scheduledLinesStr.isEmpty()) {
                    sd = scheduledLinesStr.size();
                }
                soft1Val -= (lineNumber - sd);
                softScore1 = soft1Val;
            }
        }

        int[] hardScores = new int[]{hardScore1, hardScore2};
        int[] softScores = new int[]{softScore1, softScore2};
        return BendableScore.of(hardScores, softScores);
    }

}
